<script>
/*
  function 声明的函数 this是跟随调用的上下文变化的（this是不固定的）
  箭头函数的this不随上下文改变(this不变)

  ```
  obj1.obj2.fn()  // this是obj1.obj2
  // fn的this是.前面的所有对象
  ```
  
  ```
  fn.call(obj)/fn.apply(obj) // this是obj
  // 如果用apply/call去指定fn的this，
  //  fn会用指定的参数作为自己的this
  ```
  
  ````
  fn() // this是window
  // 如果调用方法没有上下文，也没有用apply/call，
  //  fn里的this会使用全局里顶级变量当成this（非严格模式）
  ```
  
  ```
  const fn2 = fn.bind(obj)
  // fn.bind(obj) 返回一个新的function
  // fn2里this是固定的，不变的，
  fn2() // this是obj
  fn2.call(obj2) // this还是obj
  user.fn2() // this还是obj
  const fn3 = fn2.bind(obj2) // fn3里的this仍然是obj
  
  ```
  */


//   function 声明的函数 this是跟随调用的上下文变化的（this是不固定的）
//1、
window.x=100
function fn(){
    console.log(this.x);
}
fn()//没有上下文，把window当成this
    //window.x

//2、
let o1={x:1,fn:fn}
o1.fn()//上下文是o1,把o1当成this
       //取(o1.x)
let o2={x:2,fn}
o2.fn()//上下文是o2,把o2当成this
       //取(o2.x)
let a={o3:{x:3,fn}}
a.o3.fn()//上下文是o3,把o3当成this
       //取(o3.x)
// 3
// Function.prototype.call/apply/bind的第一个参数是指定函数的this
fn.call(o1)//让fn把o1当成this用
           //(o1.x)

//Function.prototype.bind返回一个新的Function
//内部的this是固定的
const fn2=fn.bind(o2)//fn2的this是o2
                     //并且它的this是固定不变的
fn2()//看起来没有上下文，但是内部的this是o2
     //结果是(o2.x)
let o4={x:4,fn:fn2}
o4.fn()//o4.fn的上下文是o4,但o4.fn的this是固定的
       //结果是(o2.x)

fn2.call(o1) //虽然call想把o1当成fn2的this,但是fn2的this是固定的，所以无效
            //结果是(o2.x)

// 箭头函数的this不随上下文改变(this不变)
//箭头函数只要创建了，它的this就不会改变了
//箭头函数的this值=它创建时候的环境的this
//1
const fn3=()=>console.log(this.x);
//当前环境this=>window
fn3()//100(取window.x)
let o5={x:5,fn:fn3}
o5.fn()//100(取window.x)
const fn4=function(){
    return ()=>console.log(this.x);
    return (function(){console.log(this.x)}).bind(this)//和上面一句效果相同
}
const fn5=fn4()//fn4()执行的时候没有指定上下文，所以当时this是window
fn5()//100(取window.x)

const o6={x:6,fn:fn4}
const fn6=o6.fn()//上下文是o6,this=o6
//返回的箭头函数生成的时候环境this=o6
fn6()//6 (取o6.x)

function a(){
    return ()=>{}
}

console.log(a()==a());//false

//容易产生歧义的写法
const o7={
    x:7,
    fn:()=>console.log(this.x)
}
o7.fn()//100(取window.x)

const o8={
    x:8,
    delayX:function(){//function没有上下文，this=window
        setTimeout(function(){
            console.log(this.x);
        },1000)
    },
    delayX2:function(){
        setTimeout(
            ()=>console.log(this.x),
            //o8.delayX2()时this=o8
            1000
            
            )
    }

}

o8.delayX()//100
o8.delayX2()//8



</script>